using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using System.Text;

namespace KaroGame.FrontEnd.Menu
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class KaroMenu : DrawableGameComponent
    {
        KaroGame baseGame;

        OptionsMenu optionsMenu;
        StartMenu startMenu;
        ResumeMenu resumeMenu;
        IMenu currentMenu, previousMenu;

        SpriteBatch spriteBatch;
        SpriteFont fontHeader, fontText;
        Texture2D background;

        bool isKeyEnterDown, isKeyDownDown, isKeyUpDown, isKeyLeftDown, isKeyRightDown, isMouseLeftPressed;
        int selectedElement;

        public KaroMenu(Game game)
            : base(game)
        {
            baseGame = game as KaroGame;


        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            spriteBatch = new SpriteBatch(baseGame.GraphicsDevice);

            background = baseGame.Content.Load<Texture2D>("menu_background");
            fontHeader = baseGame.Content.Load<SpriteFont>("Font/MenuHeader");
            fontText = baseGame.Content.Load<SpriteFont>("Font/MenuElement");

            startMenu = new StartMenu(fontText);
            resumeMenu = new ResumeMenu(fontText);
            optionsMenu = new OptionsMenu(fontText);
            currentMenu = startMenu;
            previousMenu = startMenu;

            selectedElement = 0;
            SelectElement();

            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            #region Key Events

            if (Keyboard.GetState().IsKeyDown(Keys.Enter) && !isKeyEnterDown)
            {
                isKeyEnterDown = true;

                EnterClicked();
            }
            if (Keyboard.GetState().IsKeyUp(Keys.Enter))
                isKeyEnterDown = false;

            if ((Keyboard.GetState().IsKeyDown(Keys.Down) || Keyboard.GetState().IsKeyDown(Keys.S)) && !isKeyDownDown)
            {
                isKeyDownDown = true;

                if (selectedElement < currentMenu.Elements.Count - 1)
                    selectedElement++;

                SelectElement();
            }
            if (Keyboard.GetState().IsKeyUp(Keys.Down) && Keyboard.GetState().IsKeyUp(Keys.S))
                isKeyDownDown = false;

            if ((Keyboard.GetState().IsKeyDown(Keys.Up) || Keyboard.GetState().IsKeyDown(Keys.W)) && !isKeyUpDown)
            {
                isKeyUpDown = true;

                if (selectedElement > 0)
                    selectedElement--;

                SelectElement();
            }
            if (Keyboard.GetState().IsKeyUp(Keys.Up) && Keyboard.GetState().IsKeyUp(Keys.W))
                isKeyUpDown = false;

            if (Keyboard.GetState().IsKeyDown(Keys.Left) && !isKeyLeftDown)
            {
                isKeyLeftDown = true;

                if (currentMenu.Elements[selectedElement].SelectedOption > 0)
                    currentMenu.Elements[selectedElement].SelectedOption--;
            }
            if (Keyboard.GetState().IsKeyUp(Keys.Left))
                isKeyLeftDown = false;

            if (Keyboard.GetState().IsKeyDown(Keys.Right) && !isKeyRightDown)
            {
                isKeyRightDown = true;

                if (currentMenu.Elements[selectedElement].SelectedOption < currentMenu.Elements[selectedElement].Options.Count - 1)
                    currentMenu.Elements[selectedElement].SelectedOption++;
            }
            if (Keyboard.GetState().IsKeyUp(Keys.Right))
                isKeyRightDown = false;

            #endregion

            #region Mouse Events

            int index = 0;
            int x = Mouse.GetState().X;
            int y = Mouse.GetState().Y;

            foreach (MenuElement element in currentMenu.Elements)
            {
                if (x >= element.BoundingBox.X && x <= element.BoundingBox.X + element.BoundingBox.Width &&
                   y >= element.BoundingBox.Y && y <= element.BoundingBox.Y + element.BoundingBox.Height)
                {
                    selectedElement = index;
                    SelectElement();
                }
                index++;
            }

            if (Mouse.GetState().LeftButton == ButtonState.Pressed && !isMouseLeftPressed)
            {
                isMouseLeftPressed = true;

                EnterClicked();
            }
            if (Mouse.GetState().LeftButton == ButtonState.Released)
                isMouseLeftPressed = false;

            #endregion

            base.Update(gameTime);
        }

        /// <summary>
        /// Allows the game component to draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Draw(GameTime gameTime)
        {
            spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, SaveStateMode.SaveState);

            Rectangle src = new Rectangle(0, 0, background.Width, background.Height);
            Rectangle dest = new Rectangle(0, 0, SettingsManager.Instance.ResolutionWidth, SettingsManager.Instance.ResolutionHeight);
            spriteBatch.Draw(background, dest, src, Color.White);

            spriteBatch.DrawString(fontHeader, currentMenu.Title, new Vector2(50, 50), Color.White);

            StringBuilder sb = new StringBuilder();
            Color color;
            foreach (MenuElement element in currentMenu.Elements)
            {
                sb.Remove(0, sb.Length);

                color = Color.White;
                if (element.IsSelected)
                {
                    sb.Append("> ");
                    color = Color.Yellow;
                }
                sb.Append(element.Titel);

                spriteBatch.DrawString(fontText, sb, element.Position, color);
                if (element.Options.Count > 0)
                    spriteBatch.DrawString(fontText, element.Options[element.SelectedOption].Value, new Vector2(element.Position.X + 350, element.Position.Y), color);
            }

            spriteBatch.End();

            base.Draw(gameTime);
        }

        private void SelectElement()
        {
            foreach (MenuElement element in currentMenu.Elements)
            {
                element.IsSelected = false;
            }
            currentMenu.Elements[selectedElement].IsSelected = true;
        }

        private void EnterClicked()
        {
            switch (currentMenu.Elements[selectedElement].Action)
            {
                case MenuElementAction.New:
                    SaveSettings();
                    baseGame.NewGame(GameType.PlrVsCpu);
                    baseGame.IsInMenu = false;
                    baseGame.IsGameStarted = true;
                    previousMenu = currentMenu;
                    currentMenu = resumeMenu;
                    break;
                case MenuElementAction.Resume:
                    baseGame.IsInMenu = false;
                    previousMenu = currentMenu;
                    currentMenu = resumeMenu;
                    break;
                case MenuElementAction.Options:
                    selectedElement = 0;
                    previousMenu = currentMenu;
                    currentMenu = optionsMenu;
                    optionsMenu.GetSettings();
                    break;
                case MenuElementAction.Return:
                    SaveSettings();
                    selectedElement = 0;
                    currentMenu = previousMenu;
                    break;
                case MenuElementAction.Exit:
                    baseGame.Exit();
                    break;
            }
            SelectElement();
        }

        private void SaveSettings()
        {
            foreach (MenuElement element in optionsMenu.Elements)
            {
                if (element.Titel.Contains("Mouse inverted"))
                    SettingsManager.Instance.IsMouseInverted = Boolean.Parse(element.Options[element.SelectedOption].Value);
                if (element.Titel.Contains("Ply depth"))
                    SettingsManager.Instance.PlyDepth = Int32.Parse(element.Options[element.SelectedOption].Value);
                if (element.Titel.Contains("HUD Position"))
                {
                    if (element.Options[element.SelectedOption].Value.Equals(HudPosition.Bottom.ToString()))
                        SettingsManager.Instance.HudPosition = HudPosition.Bottom;
                    else if (element.Options[element.SelectedOption].Value.Equals(HudPosition.Left.ToString()))
                        SettingsManager.Instance.HudPosition = HudPosition.Left;
                    else if (element.Options[element.SelectedOption].Value.Equals(HudPosition.Right.ToString()))
                        SettingsManager.Instance.HudPosition = HudPosition.Right;
                    else if (element.Options[element.SelectedOption].Value.Equals(HudPosition.Top.ToString()))
                        SettingsManager.Instance.HudPosition = HudPosition.Top;
                }
                if (element.Titel.Contains("Fullscreen"))
                    SettingsManager.Instance.Fullscreen = Boolean.Parse(element.Options[element.SelectedOption].Value);
                if (element.Titel.Contains("Resolution"))
                {
                    SettingsManager.Instance.ResolutionWidth = Int32.Parse(element.Options[element.SelectedOption].Value.Split('x')[0]);
                    SettingsManager.Instance.ResolutionHeight = Int32.Parse(element.Options[element.SelectedOption].Value.Split('x')[1]);
                }
            }
            baseGame.SetResolution();
        }
    }
}